#ifndef MATRIX_OPERATIONS
#define MATRIX_OPERATIONS

#include <string>
#include <time.h>
#include <vector>
using namespace std;

class MatrixOperations {

private:
	bool ellPacked, cooPacked, csrPacked;
	float * matrix; // full storage format matrix
	int numRows; // Number of rows in the matrix
	int numCols; // Number of columns in the matrix
	int numNonZeros; // Number of non-zero elements
	int maxNonZerosPerRow; // Maximum number of non-zero elements per row
	float * ellpackValues; // Values for ELLPACK format
	int * ellpackColIdx; // Column indices for ELLPACK format
	float * cooPackValues; // Values for COO / CSR format
	int * cooPackColIdx; // Column indices for COO format
	int * cooPackRowIdx; // Row indices for COO format
	int * rowPtr; // Row pointers for CSR format
	clock_t init, final; // for timers
	int cdsPackNumValues; // Values length for CDS format
	vector<float> cdsPackValues; // Values for CDS format
	vector<int> cdsPackOffsets; // Offsets for CDS format
	int numNonZeroDiags; // Number of diagonals containing non-zero elements

public:
	/*Imports a matrix from a matrix market formatted file 'name'. 
	'save' = 1 - Saves the imported matrix in memory, 0 - discards it. 
	'nrRows' - number of rows to import, set to -1 for all.*/
	MatrixOperations(string name, int save, int nrRows);

	/*Imports a matrix from a matrix market formatted file 'name'. 
	'save' = 1 - Saves the imported matrix in memory, 0 - discards it. 
	'nrRows' - number of rows to import, set to -1 for all.*/
	float * import(string name, int save, int nrRows);

	/*Returns the matrix in full storage format.*/
	float * getMatrix() { return matrix; };
	int getNumRows() { return numRows; };
	int getNumCols() { return numCols; };
	int getNumNonZeros() { return numNonZeros; };
	int getMaxNonZerosPerRow() { return maxNonZerosPerRow; };

	/* Converts the matrix to COO / CSR format. */
	void cooPackMatrix();
	float * getCooPackValues() { return cooPackValues; };
	int * getCooPackColIdx() { return cooPackColIdx; };
	int * getCooPackRowIdx() { return cooPackRowIdx; };

	/* Converts the matrix to ELLPACK format. */
	void ellPackMatrix();
	float * getEllPackValues() { return ellpackValues; };
	int * getEllPackColIdx() { return ellpackColIdx; };
	int * getCsrRowPtr() { return rowPtr; };

	/* Converts the matrix to CDS format. */
	void cdsPackMatrix();
	float * getCdsPackValues() { return &cdsPackValues[0]; };
	int getCdsPackNumValues() { return cdsPackNumValues;};
	int * getCdsPackOffsets() { return &cdsPackOffsets[0]; };
	int getNumNonZeroDiags() { return numNonZeroDiags; };
};
#endif